from tkinter import messagebox
import keyboard
from PIL import ImageTk, Image as PILImage
import tkinter as tk
import screeninfo

import mss
import mss.tools

import pyperclip

from pynput.mouse import Controller

import sys
import json
import base64

import os


def message_showinfo(message):
    root = tk.Tk()
    root.withdraw()

    messagebox.showerror("警告", message=message)

    root.quit()
    root.destroy()


def load_config(config_path="./config.json"):
    if not os.path.exists(config_path):
        raise FileNotFoundError(f"Configuration file {config_path} does not exist.")
    with open(config_path, "r", encoding="utf-8") as config_file:
        config = json.load(config_file)
    return config


try:
    config = load_config()
except Exception as e:
    message_showinfo(f"Failed to load configuration: {e}")

    exit(1)

# 全局变量，用于存储鼠标位置
position_start = None
position_end = None
listener_active = False  # 监听器是否活跃的标志
rect_id = None
canvas = None
root = None
top_level = None

If_Preview = config["if_preview"]

current_monitor=None


try:
    HOTKEY = config["hotkey"]

    OUTLINE = config["outline"]
except Exception as e:
    message_showinfo(f"Failed to read:{e}")

ScreenShot_save_path = "img/screenshot.png"

IS_PY3 = sys.version_info.major == 3
if IS_PY3:
    from urllib.request import urlopen
    from urllib.request import Request
    from urllib.error import URLError
    from urllib.parse import urlencode
    from urllib.parse import quote_plus
else:
    import urllib2  # type: ignore
    from urllib import quote_plus
    from urllib2 import urlopen  # type: ignore
    from urllib2 import Request  # type: ignore
    from urllib2 import URLError  # type: ignore
    from urllib import urlencode

import ssl

ssl._create_default_https_context = ssl._create_unverified_context


API_KEY = config["ocr"]["api_key"]

SECRET_KEY = config["ocr"]["secret_key"]


OCR_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"

"""  TOKEN start """
TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token"

"""
    获取token
"""


def fetch_token():
    params = {
        "grant_type": "client_credentials",
        "client_id": API_KEY,
        "client_secret": SECRET_KEY,
    }
    post_data = urlencode(params)
    if IS_PY3:
        post_data = post_data.encode("utf-8")
    req = Request(TOKEN_URL, post_data)
    try:
        f = urlopen(req, timeout=5)
        result_str = f.read()
    except URLError as err:
        print(err)
    if IS_PY3:
        result_str = result_str.decode()

    result = json.loads(result_str)

    if "access_token" in result.keys() and "scope" in result.keys():
        if not "brain_all_scope" in result["scope"].split(" "):
            message_showinfo("please ensure has check the  ability")
            exit()
        return result["access_token"]
    else:
        message_showinfo("please overwrite the correct API_KEY and SECRET_KEY")
        exit()


"""
    读取文件
"""


def read_file(image_path):
    f = None
    try:
        f = open(image_path, "rb")
        return f.read()
    except:
        print("read image file fail")
        return None
    finally:
        if f:
            f.close()


"""
    调用远程服务
"""


def request(url, data):
    req = Request(url, data.encode("utf-8"))
    has_error = False
    try:
        f = urlopen(req)
        result_str = f.read()
        if IS_PY3:
            result_str = result_str.decode()
        return result_str
    except URLError as err:
        print(err)


def text_preview(text):
    root_text_preview = tk.Tk()
    root_text_preview.withdraw()

    # 创建预览窗口
    preview_window = tk.Toplevel(root_text_preview)
    preview_window.title("Text Preview")
    preview_window.attributes("-topmost", True)

    width=500
    height=600

    b=10

    x=position_end[0]
    y=position_end[1]-20

    bool_1=(width+x+b>=current_monitor[0]+current_monitor[2])
    bool_2=(height+y+b>=current_monitor[1]+current_monitor[3])

    if bool_1:
        x=x-width-b
    if bool_2:
        y=y-height-b

    preview_window.geometry(f"{width}x{height}+{x}+{y}")

    text_widget = tk.Text(preview_window, wrap=tk.WORD)
    text_widget.insert(tk.END, text)
    text_widget.pack(padx=20, pady=20, expand=True, fill="both")

    def copy_text():
        text_to_copy = text_widget.get("1.0", tk.END).strip()
        pyperclip.copy(text_to_copy)

    copy_button = tk.Button(preview_window, text="复制", command=copy_text)
    copy_button.pack(pady=10)

    def on_closing():
        root_text_preview.quit()
        root_text_preview.destroy()

    preview_window.protocol("WM_DELETE_WINDOW", on_closing)  # 捕获窗口关闭事件
    root_text_preview.mainloop()


def OCR_AI():
    # 获取access token
    global ScreenShot_save_path
    token = fetch_token()

    # 拼接通用文字识别高精度url
    image_url = OCR_URL + "?access_token=" + token

    text = ""

    # 读取测试图片
    file_content = read_file(ScreenShot_save_path)

    # 调用文字识别服务
    result = request(image_url, urlencode({"image": base64.b64encode(file_content)}))

    # 解析返回结果
    result_json = json.loads(result)
    for words_result in result_json["words_result"]:
        text = text + words_result["words"]

    if If_Preview=='1':
        text_preview(text=text)
    else:
        pyperclip.copy(text)


def catchScreen(area):
    with mss.mss() as sct:
        # 构建bbox，注意mss的bbox是左上角(x, y)和宽度(width), 高度(height)
        bbox = {
            "left": area[0],
            "top": area[1],
            "width": area[2] + 1,  # +1显示完整外边框
            "height": area[3] + 1,
        }

        # 使用mss抓取指定显示器的截图
        screenshot = sct.grab(bbox)
    img = PILImage.frombytes(
        "RGB", (screenshot.width, screenshot.height), screenshot.rgb
    )
    img.save(ScreenShot_save_path)  # 使用PIL的save方法来保存图像
    OCR_AI()


def on_mouse_left_down(event):
    global position_start, rect_id, canvas, top_level
    position_start = (event.x + top_level.winfo_x(), event.y + top_level.winfo_y())
    if canvas is not None and rect_id is not None:
        canvas.delete(rect_id)
        rect_id = None

    rect_id = canvas.create_rectangle(
        event.x,
        event.y,
        event.x,
        event.y,
        outline=OUTLINE,
    )


def on_mouse_move(event):
    global position_start, position_end, rect_id, canvas, top_level
    if position_start and canvas is not None:
        position_end = (event.x + top_level.winfo_x(), event.y + top_level.winfo_y())
        canvas.coords(
            rect_id,
            position_start[0] - top_level.winfo_x(),
            position_start[1] - top_level.winfo_y(),
            event.x,
            event.y,
        )


def on_mouse_up(event):
    global position_start, position_end, root, top_level, to_destroy
    if position_start:
        position_end = (event.x + top_level.winfo_x(), event.y + top_level.winfo_y())
        x1, y1 = min(position_start[0], position_end[0]), min(
            position_start[1], position_end[1]
        )
        x2, y2 = max(position_start[0], position_end[0]), max(
            position_start[1], position_end[1]
        )
        screen_shot_area = (x1, y1, abs(x1 - x2), abs(y1 - y2))
        if top_level:
            top_level.destroy()
        if root:
            to_destroy = False

            root.quit()  # 停止主事件循环
            root.destroy()
        catchScreen(screen_shot_area)


def on_mouse_right_up(event):
    global root, top_level, listener_active
    listener_active = False

    # 销毁顶层窗口
    if top_level:
        top_level.destroy()

    # 如果主窗口存在，则退出主循环并销毁主窗口
    if root:
        root.quit()  # 停止主事件循环
        root.destroy()


def get_current_monitor():
    global current_monitor
    # 获取所有显示器的信息
    monitors = screeninfo.get_monitors()

    # 获取当前鼠标的全局坐标
    mouse = Controller()
    mouse_x, mouse_y = mouse.position

    current_monitor = (
        monitors[0].width,
        monitors[0].height,
        monitors[0].x,
        monitors[0].y,
    )

    # 查找鼠标所在的显示器
    for monitor in monitors:
        if (
            monitor.x <= mouse_x < monitor.x + monitor.width
            and monitor.y <= mouse_y < monitor.y + monitor.height
        ):
            current_monitor = (monitor.x, monitor.y, monitor.width, monitor.height)

    # 如果没有找到合适的显示器（理论上不应该发生），返回主显示器
    return current_monitor


def grab_specific_monitor(area):
    with mss.mss() as sct:
        # 构建bbox，注意mss的bbox是左上角(x, y)和宽度(width), 高度(height)
        bbox = {
            "left": area[0],
            "top": area[1],
            "width": area[2],
            "height": area[3],
        }

        # 使用mss抓取指定显示器的截图
        screenshot = sct.grab(bbox)

        # 确保screenshot不是None，并且转换为PIL Image
        if screenshot is None:
            return None

        img = PILImage.frombytes(
            "RGB", (screenshot.width, screenshot.height), screenshot.rgb
        )
        return img


def select_area():
    global root, canvas, top_level

    root = tk.Tk()
    root.withdraw()

    get_current_monitor()

    ScreenBackGround = grab_specific_monitor(area=current_monitor)

    primary_x, primary_y, primary_width, primary_height = current_monitor

    top_level = tk.Toplevel(root)
    top_level.overrideredirect(True)
    top_level.geometry(f"{primary_width}x{primary_height}+{primary_x}+{primary_y}")
    top_level.attributes("-topmost", True)

    canvas = tk.Canvas(top_level, width=primary_width, height=primary_height)
    canvas.pack()

    canvas.image_tk = ImageTk.PhotoImage(ScreenBackGround)
    canvas.create_image(0, 0, anchor=tk.NW, image=canvas.image_tk)

    canvas.bind("<Button-1>", on_mouse_left_down)
    canvas.bind("<B1-Motion>", on_mouse_move)
    canvas.bind("<ButtonRelease-1>", on_mouse_up)
    canvas.bind("<ButtonRelease-3>", on_mouse_right_up)

    root.mainloop()


# 热键事件处理函数
def on_hotkey():
    global listener_active, listener

    if API_KEY == "" or SECRET_KEY == "":
        message_showinfo("未设置API接口信息，请先注册百度智能云获取KEY")
        keyboard.unhook_all()
        sys.exit(0)

    if not listener_active:  # 防止重复启动监听器
        listener_active = True
        # 创建并启动鼠标监听器
        select_area()

        # 重置监听器活跃标志，以便可以再次通过热键启动
        listener_active = False


# 设置热键
keyboard.add_hotkey(HOTKEY, on_hotkey)
# print("Press Ctrl+Alt+E to start recording mouse movements.")
try:
    keyboard.wait()
except KeyboardInterrupt:
    pass
